// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-07-31

package src

import (
    "regexp"
    "strings"
)

const (
    DefaultKey         = "db"
    DefaultDriver      = "mysql"
    DefaultDns         = "root:pass@tcp(127.0.0.1)/test"
    DefaultMapper      = "snake"
    DefaultMaxIdle     = 2
    DefaultMaxOpen     = 30
    DefaultMaxLifetime = 60
)

var (
    DefaultEnableSession = false
    DefaultEnableLogger  = true

    regexAuthorization = regexp.MustCompile(`^([_a-zA-Z0-9-.]+):(\S+)@tcp\s*\([^)]+\)/([_a-zA-Z0-9-.]+)`)
)

// Database
// is a component for db connection configurations.
type Database struct {
    // Driver
    // database type. Accept mysql, mssql etc.
    //
    // Default: mysql
    Driver string `yaml:"driver"`

    // Dsn
    // is a list for database connection. First for them as primary and
    // others as slaves.
    Dsn []string `yaml:"dsn"`

    // Mapper
    // define.
    Mapper string `yaml:"mapper"`

    // MaxIdle
    // maximum number of idle connections maintained. The manager will close
    // unnecessary idle connections if there are too many idle connections.
    //
    // Default: 2
    MaxIdle int `yaml:"max-idle"`

    // MaxOpen
    // maximum number of connections established. The manager will block and
    // wait for an idle connection to use.
    //
    // Default: 30
    MaxOpen int `yaml:"max-open"`

    // MaxLifetime
    // a connection lifecycle.
    //
    // Default: 60
    // Unit: second
    MaxLifetime int `yaml:"max-lifetime"`

    // EnableLogger
    // is a flag for enable logger. The manager will send sql to logging
    // system if enabled.
    EnableLogger *bool `yaml:"enable-logger"`

    // EnableSession
    // is a flag for enable session. The manager will create a session
    // id for each connection.
    EnableSession *bool `yaml:"enable-session"`

    mapper     Mapper
    user, data string
}

// +---------------------------------------------------------------------------+
// | Hook methods                                                              |
// +---------------------------------------------------------------------------+

func (o *Database) After() {
    // Use
    // default driver if not set.
    if o.Driver == "" {
        o.Driver = DefaultDriver
    }

    // Use
    // default dsn if not set or empty.
    if o.Dsn == nil {
        o.Dsn = make([]string, 0)
    }
    if len(o.Dsn) == 0 {
        o.Dsn = append(o.Dsn, DefaultDns)
    }

    // Use
    // default idle count if not set.
    if o.MaxIdle == 0 {
        o.MaxIdle = DefaultMaxIdle
    }

    // Use
    // default open count if not set.
    if o.MaxOpen == 0 {
        o.MaxOpen = DefaultMaxOpen
    }

    // Use
    // default lifetime if not set.
    if o.MaxLifetime == 0 {
        o.MaxLifetime = DefaultMaxLifetime
    }

    // Use
    // default logger state if not set.
    if o.EnableLogger == nil {
        o.EnableLogger = &DefaultEnableLogger
    }

    // Use
    // default session state if not set.
    if o.EnableSession == nil {
        o.EnableSession = &DefaultEnableSession
    }

    // Mapper
    // for database, table and field name.
    if o.Mapper == "" {
        o.Mapper = DefaultMapper
    }

    // Generate mapping type.
    switch strings.ToLower(o.Mapper) {
    case "gonic":
        o.mapper = GonicMapper{}
    case "prefix":
        o.mapper = PrefixMapper{}
    case "same":
        o.mapper = SameMapper{}
    case "snake":
        o.mapper = SnakeMapper{}
    case "suffix":
        o.mapper = SuffixMapper{}
    default:
        o.mapper = SnakeMapper{}
    }

    // Generate authorization.
    for _, s := range o.Dsn {
        if m := regexAuthorization.FindStringSubmatch(s); len(m) > 0 {
            o.user = m[1]
            o.data = m[3]
        }
    }
}
